package pumps

import (
	"context"
	"net/http"

	"gitee.com/youkelike/ziam/zanalytics"
	"gitee.com/youkelike/ziam/zerrors"
	"gitee.com/youkelike/zlog"
	"github.com/mitchellh/mapstructure"
	"github.com/ory/ladon"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

type PrometheusConf struct {
	Addr string `mapstructure:"listen_address"`
	Path string `mapstructure:"path"`
}

type PrometheusPump struct {
	conf *PrometheusConf
	// Per service
	TotalStatusMetrics *prometheus.CounterVec

	CommonPumpConfig
}

func (p *PrometheusPump) New() Pump {
	newPump := PrometheusPump{}
	newPump.TotalStatusMetrics = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Name: "iam_user_authorization_status_total",
			Help: "authorization effect per user",
		},
		[]string{"code", "username"},
	)

	prometheus.MustRegister(newPump.TotalStatusMetrics)

	return &newPump
}

func (p *PrometheusPump) GetName() string {
	return "Prometheus Pump"
}

func (p *PrometheusPump) Init(conf interface{}) error {
	p.conf = &PrometheusConf{}
	err := mapstructure.Decode(conf, &p.conf)
	if err != nil {
		zlog.Fatalw("Failed to decode configuration: %s", err.Error())
	}

	if p.conf.Path == "" {
		p.conf.Path = "/metrics"
	}

	if p.conf.Addr == "" {
		return zerrors.New("prometheus listen_addr not set")
	}

	zlog.Infow("Starting prometheus listener on: %s", p.conf.Addr)

	http.Handle(p.conf.Path, promhttp.Handler())

	go func() {
		zlog.Fatalw(http.ListenAndServe(p.conf.Addr, nil).Error())
	}()

	return nil
}

func (p *PrometheusPump) WriteData(ctx context.Context, data []interface{}) error {
	zlog.Debugw("Writing %d records", len(data))

	for _, item := range data {
		record, _ := item.(zanalytics.AnalyticsRecord)
		code := "0"
		if record.Effect != ladon.AllowAccess {
			code = "1"
		}

		p.TotalStatusMetrics.WithLabelValues(code, record.Username).Inc()
	}

	return nil
}
